import { Feature, Map, View } from 'ol'
import TileLayer from 'ol/layer/Tile'
import { XYZ } from 'ol/source'
import { onMounted, createApp, defineComponent } from 'vue'
import { isFunction } from '@vue/shared'
import { ref, unref, toRaw, computed } from '@vue/reactivity'
import type { AtPixelOptions, MapOptions } from 'ol/Map'
import VectorLayer from 'ol/layer/Vector'
import VectorSource from 'ol/source/Vector'
import { Draw } from 'ol/interaction'
import type { DrawEvent, Options as DrawOption } from 'ol/interaction/Draw'
import type { Type as DrawType } from 'ol/geom/Geometry'
import { MaybeRef, MaybeRefNull } from '@/types/is'

export type DrawTypes = DrawType | 'None'

const mapObj: Map | null = null

export type TianDiTuType = 'vec_w' | 'cia_w'
const useTianDiTu = () => {
    /**
     * 
     * @param type 天地图类型
     * @param key 天地图key
     * @param properties 属性
     * @returns 
     */
    function createTitleLayer(type: TianDiTuType, key: string, properties: { [x: string]: any } = {}) {
        return new TileLayer({
            source: new XYZ({
                url: `http://t0.tianditu.gov.cn/DataServer?T=${type}&x={x}&y={y}&l={z}&tk=${key}`,
                crossOrigin: 'anonymous'
            }),
            properties: {
                name: "tian_di_tu_title_layer",
                ...properties
            }
        })
    }

    const key_ = 'b945c29c5388432e34b51b5d824d8157'

    /**
     * 初始化地图
     * @param key 天地图key
     * @param mapOpt {@link ol/Map}
     * @returns 
     */
    const initMap = (key: string = key_, mapOpt: MapOptions = {}) => {
        const opt = Object.assign({
            target: 'map',
            layers: [
                createTitleLayer('vec_w', key),
                createTitleLayer('cia_w', key),
            ],
            controls: [], // 不包含任何控制组件
            //视图
            view: new View({
                center: [113.75395, 34.76572],
                zoom: 8,
                projection: "EPSG:4326"
            })
        }, mapOpt)
        return new Map(opt)
    }

    const simpleMap = (target: string | HTMLElement) => {
        return new Map({
            target,
            layers: [
                createTitleLayer('vec_w', key_),
                createTitleLayer('cia_w', key_),
            ],
            controls: [], // 不包含任何控制组件
            //视图
            view: new View({
                center: [113.75395, 34.76572],
                zoom: 8,
                projection: "EPSG:4326"
            })
        })
    }



    return {
        createTitleLayer,
        initMap,
        key: key_,
        simpleMap
    }
}

const useMap = () => {

    const map = computed(() => mapObj.value)

    const setMap = async (opt: MapOptions, postrender: undefined | ((map: Map) => void) = undefined) => {
        mapObj.value = new Map(opt)
        mapObj.value.once("postrender", () => {
            postrender && postrender(mapObj.value as Map)
            return Promise.resolve(mapObj)
        })
    }

    const mountMap = (opt: MapOptions) => {
        onMounted(() => mapObj.value = new Map(opt))
    }

    return {
        map,
        setMap,
        mountMap
    }
}

// 页面元素全屏
const useFullScreen = (target: string) => {
    /** 全屏  ==========================  start  ==============*/
    const isFull = ref(false)
    const fullScreen = () => {
        const mapElement = document.getElementById(target)
        if (!document.fullscreenElement) {
            mapElement?.requestFullscreen()
        } else {
            document.exitFullscreen()
        }
        isFull.value = !isFull.value
    }
    /** 全屏  ==========================  end  ==============*/
    return {
        isFull,
        fullScreen
    }
}

export interface FyDrawOption {
    // name
    name: string,
    map: MaybeRefNull<Map | null>,
    show?: boolean,
    // 绘制结束
    drawend?: (event: DrawEvent, drawLayer: VectorLayer<VectorSource>) => void,
    // Draw 配置
    drawOpt?: DrawOption[],
    // 绘制类型
    drawType: MaybeRef<DrawTypes>
}

/**
 * 绘制
 * @param opt 配置
 * @returns 
 */
const useDraw = (opt: FyDrawOption) => {
    let map_: Map | null = null
    let show_ = opt.show || true
    const drawLayerName = `draw_${opt.name}`
    
    // 创建一个用于存放要素的矢量图层
    const drawLayer = new VectorLayer({
        source: new VectorSource({
            wrapX: false
        }),
        properties: {
            name: drawLayerName
        }
    })

    
    // 是否已经开始绘制
    const isStarted = () => {
        return !!getMap()?.getInteractions().getArray().find(item => item === draw)
    }
    //  图层是否挂在
    const isLayerMounted = () => !!getMap()?.getLayers().getArray().find((item) => item.get("name") === drawLayerName)
    // 是否已经显示
    const isShowed = () => isLayerMounted() && drawLayer.getVisible()
    
    // 设置 map 地图对象
    const setMap = (map: Map) => map_ = map
    // 获取 map 对象
    const getMap = () => toRaw(unref(opt.map)) || map_
    // 创建一个交互式绘制工具，用于点击选点
    let draw: Draw
    // 画完操作事件
    const drawendEvent = (event: DrawEvent) => opt.drawend?.(event, drawLayer)

    
    // 隐藏图层
    const hide = () => isShowed() && drawLayer.setVisible(false)
    // 显示图层
    const show = () => {
        drawLayer.setVisible(true)
        !isLayerMounted() && getMap()?.addLayer(drawLayer)
    }
    // 清空图层
    const clear = () => drawLayer.getSource()?.clear()

    drawLayer.setVisible(false)
    /**
     * 开始绘制
     * @returns 
     */
    const start = () => {
        const map = getMap()
        if(!map) return;
        if(isStarted()){
            end()
        }
        // 初始化
        const type = unref(opt.drawType)
        if(type === 'None'){
            return
        }
        show_ && show()
        draw = new Draw({
            source: drawLayer.getSource() || undefined,
            type
        })
        // 监听画完操作事件
        opt.drawend && isFunction(opt.drawend) && draw.on('drawend', drawendEvent)
        // 添加交互式绘制工具到地图
        map.addInteraction(draw)
    }
    /**
     * 结束绘制
     * @param map 地图对象
     * @returns Interaction | undefined
     */
    const end = () => getMap()?.removeInteraction(draw)

    return {
        start,
        end,
        setMap,
        hide,
        show,
        clear
    }
}

const usePopover = () => {}

export interface FyMapDialogOption {
    targetId: string,
    append?: boolean
}




const useDialog = (content: any, opt:FyMapDialogOption = { targetId : 'uuuu'}) => {
    const {
        targetId = 'uuuu',
        append = true
    } = opt

    // const containder = append ? document.getElementById(targetId) : document.createElement('div')

    createApp(content).mount(`#${targetId}`)
}

export {
    useTianDiTu,
    useMap,
    useFullScreen,
    useDraw
}